package com.foohoo.benchmark.collection;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

/**
 * 测试不同的LinkedList集合遍历方式的性能
 * Benchmark                                     Mode  Cnt       Score         Error  Units
 * LinkedListLoop.loopLinkedListWithFor          avgt    3  697100.211 ± 1735267.571  ns/op
 * LinkedListLoop.loopLinkedListWithForEach      avgt    3   11303.521 ±   18693.398  ns/op
 * LinkedListLoop.loopLinkedListWithIterator     avgt    3   13006.622 ±   30377.820  ns/op
 * LinkedListLoop.loopLinkedListWithPollFirst    avgt    3       7.526 ±       6.119  ns/op
 * LinkedListLoop.loopLinkedListWithPoolLast     avgt    3       8.495 ±      21.720  ns/op
 * LinkedListLoop.loopLinkedListWithRemoveFirst  avgt    3       8.136 ±      10.574  ns/op
 * LinkedListLoop.loopLinkedListWithRemoveLast   avgt    3       7.698 ±       2.421  ns/op
 * 一句话结论: 无损方法中foreach最快，有损方法快了三个数量级；千万不要用指定索引的方式获取
 *
 * @author mzdbxqh
 * @date 2020-10-23 16:56
 **/
@Slf4j
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
@State(Scope.Benchmark)
@Threads(1)
public class LinkedListLoop {

	private LinkedList<Integer> linkedList = new LinkedList<>();

	private static final int LIST_SIZE = 1024;

	@Setup(Level.Invocation)
	public void initialize() {
		for (int i = 0; i < LIST_SIZE; i++) {
			linkedList.add(i);
		}
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithFor(Blackhole bh) {
		for (int i = 0; i < linkedList.size(); i++) {
			bh.consume(linkedList.get(i));
		}
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithForEach(Blackhole bh) {
		for (Integer i : linkedList) {
			bh.consume(i);
		}
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithIterator(Blackhole bh) {
		for (Iterator i = linkedList.iterator(); i.hasNext(); ) {
			bh.consume(i.next());
		}
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithPollFirst(Blackhole bh) {
		Integer i = linkedList.pollFirst();
		do {
			bh.consume(i);
			i = linkedList.pollFirst();
		} while (null != i);
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithPoolLast(Blackhole bh) {
		Integer i = linkedList.pollLast();
		do {
			bh.consume(i);
			i = linkedList.pollLast();
		} while (null != i);
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithRemoveFirst(Blackhole bh) {
		int size = linkedList.size();
		for (int i = 0; i < size; i++) {
			Integer j = linkedList.removeFirst();
			bh.consume(j);
		}
	}

	@Benchmark
	@OperationsPerInvocation(LIST_SIZE)
	public void loopLinkedListWithRemoveLast(Blackhole bh) {
		int size = linkedList.size();
		for (int i = 0; i < size; i++) {
			Integer j = linkedList.removeLast();
			bh.consume(j);
		}
	}
}
